//=======================================================================================
//=======================================================================================

#include <limits.h>
#include "miniwin.cpp"
#include "minicon.cpp"
#include <math.h>

//=======================================================================================
//=======================================================================================

bool seq_mode = false;

#if _MSC_VER < 1400
# define _snwprintf_s(o, m1, m2, f, a) _snwprintf(o,m1,f,a)
# define _A_ ""
# define LA_ L""
#else
# define _A_ "aA"
# define LA_ L"aA"
#endif

void version()
{ Con::o(Win::vers(seq_mode ? "seq" : "printf")); }

void usage()
{
   if (seq_mode) {
      Con::o(
         "Usage:\r\n"
         "  seq.exe [Options] Last\r\n"
         "  seq.exe [Options] Fist Last\r\n"
         "  seq.exe [Options] First Step Last\r\n"
         "\r\n"
         "Prints numbers from First to Last with Step increment.\r\n"
         "Start Default value is 1. Step default value is 1*sign(Last-First).\r\n"
         "\r\n"
         "Options:\r\n"
         "  -s, --separator=Str  set separator string (default is newline)\r\n"
         "  -f, --format=Format  set output float format (default depends on range)\r\n"
         "  -w, --equal-width    add zero(es) to make fixed length (ignored with -f)\r\n"
         "  -L, --limit=Limit    set maximum number of iterations (default 1000000)\r\n"
         "  --help               display this help and exit\r\n"
         "  --version            output version information and exit\r\n"
         "  --cp=CodePage        set output code page\r\n"
         "\r\n"
         "Examples:\r\n"
         "  seq 10\r\n"
         "  seq -wL 30 --separator=, 61 2.1 100\r\n"
         "  seq --format=\"Dir\\\\File%03.0f.out\" 99 1\r\n"
      );
      return;
   }
   Con::o(
    "Usage:\r\n"
    "  printf.exe [Options]\r\n"
    "  printf.exe FORMAT [ARGUMENT] ...\r\n"
    "\r\n"
    "Print ARGUMENT(s) according to FORMAT.\r\n"
    "\r\n"
    "FORMAT controls the output as in C printf. Interpreted sequences are:\r\n"
    "  \\OOO         character with octal value OOO\r\n"
    "  \\xHH         character with hex value 0xHH\r\n"
    "  \\uHHHH       Unicode character with hex value 0xHHHH\r\n"
    "  \\\\           backslash\r\n"
    "  \\a           audible BEL\r\n"
    "  \\b           backspace\r\n"
    "  \\f           form feed\r\n"
    "  \\n           new line\r\n"
    "  \\r           return\r\n"
    "  \\t           horizontal tab\r\n"
    "  \\v           vertical tab\r\n"
    "  \\PQOALGUISE  (%\"'&<>^| =)\r\n"
    "  %%           a single %\r\n"
    "  %b           ARGUMENT as a string with '\\' escapes interpreted\r\n"
    "\r\n"
    "and all C format specifications ending with one of diouxXfeEgG" _A_ "cs,\r\n"
    "with ARGUMENTs converted to proper type first. Variable widths are handled.\r\n"
    "Positional parameters (%n$... *m$) are handled too.\r\n" 
    "\r\n"
    "If there are more string operands than format specifiers, the format string is\r\n"
    "reused from the beginning. If there are fewer string operands than format specifiers,\r\n"
    "then string specifiers are treated as if empty strings were supplied,\r\n"
    "numeric conversions are treated as if 0 was supplied.\r\n"
    "\r\n"
    "Options:\r\n"
    "  --help        display this help and exit\r\n"
    "  --version     output version information and exit\r\n"
    "  --cp=CodePage set output code page\r\n"
    "\r\n"
    "Examples:\r\n"
    "  printf \"%5d%4d\\n\" 1 21 321 4321 54321\r\n"
    "  printf \"%s, %s %d, %d:%.2d\\n\" %weekday% %month% %day% %hour% %min%\r\n"
    "  printf \"%1$s, %3$d. %2$s, %4$d:%5$.2d\\n\" monday october 4 17 41\r\n"
    "  printf \"%1$s :: %1$f :: %1$'f :: %1$,f\" 1234567.123456789\r\n"
//  "\r\n"
   );
}

//=======================================================================================
//=======================================================================================

static bool eq( WCHAR* &pw, const char *opt, bool no_opt = false )
{
   if ( !pw || !opt )
      return false;

   int i;
   for ( i = 0; opt[i]; ++i ) {
      if ( (WCHAR)opt[i] != pw[i] ) return false;
   }
   if ( no_opt || !pw[i] ) { pw = NULL; return true; } // empty long option
   if ( L'=' != pw[i] ) return false;        // not equal
   pw[i] = L'\0'; pw += i + 1; return true;  // long option with value
}

//---------------------------------------------------------------------------------------

static unsigned __int64 wtou64( const WCHAR *pw, unsigned base, unsigned *plen )
{
   unsigned __int64 val = 0, val0; unsigned ndig = 0, mlen = plen ? *plen : 0;
   if ( 0 == base ) { base = 10; if ( L'0' == *pw ) base = 8; }
   for (;;) {
      unsigned dig = 100;
      if      ( *pw >= L'0' && *pw <= L'9' ) dig = (int)(*pw - L'0');
      else if ( *pw >= L'a' && *pw <= L'z' ) dig = (int)(*pw - L'a') + 10;
      else if ( *pw >= L'A' && *pw <= L'Z' ) dig = (int)(*pw - L'A') + 10;
      if ( dig >= base ) break;
      val = (val0 = val) * base + dig; // overflow
      if (val < val0) val = _UI64_MAX;
      ++ndig; ++pw;
      if ( mlen > 0 && ndig >= mlen ) break;
   }
   if (plen) *plen = ndig;
   return val;
}

static unsigned wtou( const WCHAR *pw, unsigned base, unsigned *plen )
{
   unsigned __int64 u64 = wtou64(pw, base, plen);
   return (unsigned)(u64 > UINT_MAX ? UINT_MAX : u64);
}

//---------------------------------------------------------------------------------------

static void get_sign_base( const WCHAR* &pw, int &sign, int &base )
{
   while (*pw == L' ' || *pw == L'\t') ++pw;
   sign = +1;
   base = 10;
   if ( L'+' == *pw ) ++pw;
   else if ( L'-' == *pw ) { ++pw; sign = -1; }
   else if ( L'0' == *pw ) {
      ++pw; base = 8;
      if      ( L'x' == *pw || L'X' == *pw ) { ++pw; base = 16; }
      else if ( L'b' == *pw || L'B' == *pw ) { ++pw; base =  2; }
      else if ( L'd' == *pw || L'D' == *pw ) { ++pw; base = 10; }
      else if ( L'z' == *pw || L'Z' == *pw ) { ++pw; base = 36; }
   }
}

static unsigned __int64 wtou64( const WCHAR *pw )
{
   if ( !pw ) return 0;
   int sign, base;
   get_sign_base(pw, sign, base);
   if (sign < 0) return 0;
   return wtou64(pw, base, NULL);
}

static __int64 wtoi64( const WCHAR *pw )
{
   if ( !pw ) return _I64_MIN;
   int sign, base;
   get_sign_base(pw, sign, base);
   unsigned __int64 u64 = wtou64(pw, base, NULL), um = (unsigned __int64)_I64_MAX;
   if ( sign > 0 ) return (__int64)(u64 > um ? um : u64);
   ++um;
   return (__int64)(u64 > um ? 0-um : 0-u64);
}

//---------------------------------------------------------------------------------------

static bool getargs( int& argc, WCHAR** argv )
{
   WCHAR *cmd = Win::strdup(::GetCommandLineW());

   int ma = argc, na = 0;
   if ( !cmd || !cmd[0] )
   { argc = na; return false; }

   WCHAR *pw = cmd;
   for (;;)
   {
      while ( *pw && *pw <= L' ' ) ++pw;
      if ( !*pw || na >= ma ) break;

      WCHAR *po = argv[na++] = pw; WCHAR q = L'\0';
      for (;;) {
         if ( !q && (L'"' == *pw || L'\'' == *pw) ) { q = *pw; ++pw; continue; }
         if ( q && q == *pw ) { q = L'\0'; ++pw; continue; }
         if ( !*pw ) { *po = L'\0'; break; }
         if ( *pw <= L' ' && !q ) { ++pw; *po = L'\0'; break; }
         *po++ = *pw++;
      }
   }

   argc = na;
   return true;
}

//---------------------------------------------------------------------------------------

static int unescape( WCHAR *str )
{
   unsigned val, len; int v;
   WCHAR *pi, *po;
   for ( pi = po = str; *pi; ++pi )
   {
      if ( L'\\' != *pi ) { *po++ = *pi; continue; }
      ++pi;
      v = -1;
      switch ( *pi ) {
         case L'\\': *po++ = L'\\'; break;
         case 'a':   *po++ = L'\a'; break;
         case 'b':   *po++ = L'\b'; break;
         case 'f':   *po++ = L'\f'; break;
         case 'n':   *po++ = L'\n'; break;
         case 'r':   *po++ = L'\r'; break;
         case 't':   *po++ = L'\t'; break;
         case 'v':   *po++ = L'\v'; break;
         case L'P':  *po++ = L'%';  break; //!!! MY !!!
         case L'Q':  *po++ = L'"';  break; //!!!!!!!!!!
         case L'O':  *po++ = L'\''; break; // extension
         case L'A':  *po++ = L'&';  break; // to
         case L'L':  *po++ = L'<';  break; // play
         case L'G':  *po++ = L'>';  break; // with
         case L'I':  *po++ = L'|';  break; // windows
         case L'S':  *po++ = L' ';  break; // shell
         case L'U':  *po++ = L'^';  break; //!!!!!!!!!!
         case L'E':  *po++ = L'=';  break; //!!!!!!!!!!
         case L'0': case L'1': case L'2': case L'3': case L'4': case L'5': case L'6': case L'7':
            len = 3; v = (int)wtou(pi, 8, &len); pi += len - 1;
         break;
         case 'x':
            len = 2; v = (int)wtou(pi+1, 16, &len); pi += 1 + len - 1;
         break;
         case 'u':
            len = 4; val = wtou(pi+1, 16, &len); pi += 1 + len - 1;
            *po++ = (WCHAR)val;
         break;
      }
      if ( v >= 0 ) {
         *po = (WCHAR)v;
         ::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&v, 1, po, 1);
         ++po;
      }
   }
   *po = L'\0';
   return (int)(unsigned)(po - str);
}

//=======================================================================================
#if defined(_WIN64) || defined(_DEBUG) || !defined(_M_IX86)
#else
__declspec(naked)
DWORD __fastcall lldiv( __int64 &dividend, DWORD divisor )
{
   // lea   ecx, dividend
   // mov   edx, divisor
   // call  lldiv
   #define divd_LO_  dword ptr [ecx]
   #define divd_HI_  dword ptr [ecx+4]
   #define divisor_  edx
   __asm {
      push  ebx
         mov   ebx, divisor_
         mov   eax, divd_HI_
         xor   edx, edx
         div   ebx
         mov   divd_HI_, eax
         mov   eax, divd_LO_
         div   ebx
         mov   divd_LO_, eax
         xchg  edx, eax
         pop   ebx
         ret
   }
   (void)dividend, divisor;
}
#endif
//=======================================================================================
//=======================================================================================

static const int arg_max = 512;
static const int arg_len_max = 64 * 1024;

//=======================================================================================

static void check_alt_mode( WCHAR *pname )
{
   WCHAR *pe = pname + ::lstrlenW(pname) - 1;
   if (pe >= pname && *pe == L'"') --pe;
   while (pe >= pname && *pe != L'\\' && *pe != L'/' && *pe != L':' && *pe != L'"') --pe;
   ++pe;
   if (eq(pe, "seq", true))
      seq_mode = true;
}

static double tod( WCHAR *pw, int &prec )
{
   WCHAR *pe, *pd;
   double d = wcstod(pw, &pe); *pe = L'\0';
   int ndec = 0;
   if ((double)(__int64)d != d) { //not int
      pd = wcsrchr(pw, L'.');
      if (!pd) ndec = -1; else
      {
         while (pd[1] >= L'0' && pd[1] <= L'9') { ++pd; ++ndec; }
      }
   }
   if (prec >= 0)
   { if (ndec < 0 || ndec > prec) prec = ndec; }
   return d;
}

static int seq( int argc, WCHAR **argv )
{
   __int64 limit=1000*1000; bool eq_width=false; WCHAR *fmt=0, *sep=L"\r\n";
   WCHAR *pw, cw; int skip = 1;
   while (skip < argc && argv[skip][0] == L'-') {
      pw = argv[skip++] + 1;
      if ((cw = *pw++) == L'-') {
         if (eq(pw, "help"))
         { usage(); return 0; }
         if (eq(pw, "version"))
         { version(); return 0; }
         if (eq(pw, "cp") && pw)
         { Con::setCP(pw); continue; }

         if (eq(pw, "separator") && pw)
         { unescape(sep = pw); continue; }
         if (eq(pw, "format") && pw)
         { fmt = pw; continue; }
         if (eq(pw, "limit") && pw)
         { limit = wtoi64(pw); continue; }
         if (eq(pw, "equal-width"))
         { eq_width = true; continue; }

         usage(); return 40;
      }
      while (L'\0' != cw) {
         switch (cw) {
            case L's':
               if (skip >= argc) { usage(); return 41; }
               unescape(sep = argv[skip++]);
            break;
            case L'f':
               if (skip >= argc) { usage(); return 42; }
               fmt = argv[skip++];
            break;
            case L'L':
               if (skip >= argc) { usage(); return 43; }
               limit = wtoi64(argv[skip++]);
            break;
            case L'w':
               eq_width = true;
            break;
            default:
               usage();
            return 44;
         }
         cw = *pw++;
      }
   }
   if (skip >= argc)
   { usage(); return 45; }

   int prec = 0;
   double first = 1.0, step = 1.0,  last = tod(argv[skip++], prec);
   if (skip < argc) { first = last; last = tod(argv[skip++], prec); }
   if (last < first) step = -1.0;
   if (skip < argc) { step  = last; last = tod(argv[skip++], prec); }
   if (skip < argc)
   { usage(); return -46; }

   double eps = fabs(first)/1e+14, e1 = fabs(last)/1e+14, e2 = fabs(step)/1e+2;
   if (eps < e1) eps = e1; if (eps < e2) eps = e2;

   WCHAR ff[32], t[3072]; t[3071] = L'\0';
   if (!fmt) {
      fmt = ff;
      if (prec < 0) ::lstrcpyW(ff, L"%g"); else wsprintfW(ff, L"%%.%df", prec);
      if (eq_width) {
         int n1 = _snwprintf_s(t, 64, 64, ff, first);
         int n2 = _snwprintf_s(t, 64, 64, ff, first + step);
         double tlast = first, tlimit = (double)(limit-1), teps = step >= 0.0 ? eps : -eps;
         if (step != 0.0) {
            tlimit = (double)(__int64)((last+teps - first)/step);
            if (limit > 0 && tlimit > limit-1) tlimit = (double)(limit-1);
            tlast = first + step * tlimit;
         }
         int n3 = _snwprintf_s(t, 64, 64, ff, tlast);
         if (n1 < n2) n1 = n2; if (n1 < n3) n1 = n3;
         if (prec < 0) wsprintfW(ff,L"%%0%dg",n1); else wsprintf(ff,L"%%0%d.%d%f",n1,prec);
      }
   }
   else unescape(fmt);

   bool need_sep = false;
   for (;;) {
      if (need_sep) Con::o(sep); else need_sep = true;
      _snwprintf_s(t, 3071, 3071, fmt, first);
      Con::o(t);
      if (limit > 0 && --limit == 0) break;
      if (fabs(last-first) < eps) break;
      first += step;
      if ((step > 0.0 && first >= last+eps) || (step < 0.0 && first <= last-eps)) break;
   }

   return 0;
}

//=======================================================================================
//=======================================================================================

static void width_prec(
   const WCHAR* &pw, WCHAR* &pf, WCHAR** argv,int argc,int skip,int &curr, bool &pos_mode)
{
   unsigned long un = (unsigned long)-1;
   WCHAR *pe;

   if ( *pw >= L'0' && *pw <= L'9' ) {
      un = wcstoul(pw, &pe, 10); pw = pe; 
   }
   else if ( *pw == L'*' ) {
      ++pw;
      if (*pw >= L'1' && *pw <= L'9') {
         un = wcstoul(pw, &pe, 10);
         if (*pe == L'$') ++pe;
         pw = pe;
         pos_mode = true;
      }
      else un = (unsigned long)curr++ - skip;

      if (skip+un >= (unsigned long)argc) un = 0;
      else {
         un = wcstoul(argv[skip+(int)un], NULL, 0);
      }
   }

   if (un != (unsigned long)-1) pf += wsprintf(pf, L"%lu", un);
}

int wmain( int unused_argc, WCHAR **unused_argv )
{
   WCHAR **argv = NULL; Win::alloc((void* &)argv, (int)(arg_max * sizeof(WCHAR *)));
   WCHAR *out1 = NULL; Win::alloc((void* &)out1, (int)(arg_len_max * sizeof(WCHAR)));
   int rc = 0, argc = arg_max, current, skip = 1;
   const WCHAR *format;
   bool positional_mode;

   OSVERSIONINFOA oi;
   Win::bzero(&oi, sizeof(oi));
   oi.dwOSVersionInfoSize = (DWORD)sizeof(OSVERSIONINFOA);
   if (!::GetVersionExA((LPOSVERSIONINFOA)&oi) || oi.dwPlatformId < VER_PLATFORM_WIN32_NT)
   {
      Con::err(true);
      Con::o("Win 9x is not supported"); Con::n();
      return 9;;
   }

   Win::init(); Con::init();

   getargs(argc, argv);
   check_alt_mode(argv[0]);
#if defined(_DEBUG) && 0
   seq_mode = true;
#endif
   if (seq_mode) {
      rc = seq(argc, argv); goto e;
   }

   while (skip < argc) {
      WCHAR *pw = argv[skip];
      if (L'-' != *pw++) break;
      if (L'-' != *pw++) break;
      if (!pw[0]) { ++skip; break; }
      if (eq(pw, "help")) { 
         usage(); return 0;
      }
      if (eq(pw, "version")) { 
         version(); return 0;
      }
      if (eq(pw, "cp") && pw) { 
         Con::setCP(pw); ++skip; continue;
      }
      break;
   }

   if (argc <= skip) {
      Con::o("ERR -- Missed parameter(s)\r\nTry to use '--help' option\r\n");
      rc = 1; goto e;
   }

   unescape(argv[skip]);
   format = argv[skip];

   positional_mode = false;
   current = skip + 1;
   do {
      const WCHAR *pw = format;
      while (*pw) {
         if ( L'%' != *pw ) {
            Con::o(pw++, 1); continue;
         }
         if ( L'%' == pw[1] ) {
            Con::o(pw, 1); pw += 2;
         }
         
         const WCHAR *p0 = pw++;
         WCHAR f1[64], *pf = f1, *pe, thousand = L'\0';
         int pos = 0;
         unsigned long un;

         *pf ++ = L'%';

         // %[pos$][flags][width][.prec][size]type
         //   ^^^^
         if (*pw >= L'1' && *pw <= L'9') {
            un = wcstoul(pw, &pe, 10);
            if ( *pe == L'$' && un > 0 && un < arg_max ) {
               pw = pe + 1; pos = (int)un; positional_mode = true;
            }
         }
         
         // %[pos$][flags][width][.prec][size]type
         //         ^^^^^
         for(;;) {
            if ( wcschr(L"-+#0 ", *pw) ) *pf++ = *pw++;
            else if (*pw == L'\'' || *pw == L',' || *pw == '`') { thousand = *pw++; }
            else break;
         }

         // %[pos$][flags][width][.prec][size]type
         //                ^^^^^
         width_prec(pw, pf, argv,argc,skip,current, positional_mode);
         
         // %[pos$][flags][width][.prec][size]type
         //                       ^^^^^
         if ( *pw == L'.' ) {
            *pf++ = *pw++;
            width_prec(pw, pf, argv,argc,skip,current, positional_mode);
         }

         // %[pos$][flags][width][.prec][size]type
         //                              ^^^^
         WCHAR *szty = pf;
         switch (*pw) {
            case L'h':                                                    //h
               *pf++ = L'h'; ++pw; if (*pw == L'h') ++pw;                 //hh -> h
            break;
            case L'l':
               *pf++ = *pw++;                                             //l
               if (*pw == L'l') { lstrcpyW(pf-1, L"I64"); pf += 2; ++pw; }//ll -> I64
            break;
            case L'q': case L'j':                                         //q -> I64
               lstrcpyW(pf, L"I64"); pf += 3; ++pw;                       //j -> I64
            break;
            case L'z': case L'Z': case L't':                              //z -> I
               *pf++ = L'I'; ++pw;                                        //Z -> I
            break;                                                        //t -> I
            case L'L':
               *pf++ = L'l'; ++pw;                                        //L -> l
            break;
            case L'I':
               *pf++ = *pw++;                                             //I
               if ((*pw==L'3' && pw[1]==L'2')||(*pw==L'6' && pw[1]==L'4'))//I32
               { *pf++ = *pw++; *pf++ = *pw++; }                          //I64
            break;
            default: break;
         }

         // %[pos$][flags][width][.prec][size]type
         //                                   ^^^^
         if ( *pw && wcschr(L"csdiouxXeEfgGp" LA_ L"b", *pw) ) *pf++ = *pw;
         else if ( *pw == L'C' ) *pf++ = L'c';
         else if ( *pw == L'S' ) *pf++ = L's';
         else if ( *pw == L'F' ) *pf++ = L'f';
         else {
            Con::o(p0, (int)(size_t)(pw-p0));
            Con::o(L"<BAD FORMAT>");
            continue;
         }
         *pf = L'\0'; ++pw;

         // read argument
         //
         union u {
            WCHAR  c;
            __int16 hi; unsigned __int16 hu;
            __int32 ii; unsigned __int32 iu;
            __int64 li; unsigned __int64 lu;
            double d;
            WCHAR *p;
         } arg;
         memset(&arg, 0, sizeof(arg));
         if (pos <= 0) pos = current++ - skip;
         if ( skip + pos < argc ) {
            WCHAR *pd = argv[skip + pos];
            switch ( pf[-1] ) {
               case L'b':
                  pd = Win::strdup(pd); unescape(pd);
               case L'p': case L's':
                  arg.p = pd;
               break;
               case L'f': case L'e': case L'E': case L'g': case L'G': case L'a': case L'A':
                  arg.d = wcstod(pd, NULL);
               break;
               default:
                  while (*pd == L' ' || *pd == L'\t') ++pd;
                  if (*pd == L'+' || *pd == L'-') arg.li = wtoi64(pd);
                  else arg.lu = wtou64(pd);
               break;
            }
         }

         // format argument
         //
         size_t mo = arg_len_max; int no = 0;
         switch ( pf[-1] ) {
             case L'b':
                pf[-1] = L's';
             case L'p': case L's':
                no = _snwprintf_s (out1, mo, mo, f1, arg.p ? arg.p : L""); 
             break;
             case L'f': case L'e': case L'E': case L'g': case L'G': case L'a': case L'A':
                no = _snwprintf_s(out1, mo, mo, f1, arg.d); 
             break;
             case L'c':
                arg.c = (WCHAR)arg.lu;
                no = _snwprintf_s(out1, mo, mo, f1, arg.c); 
             break;
             default:
                bool sign = pf[-1] == L'd' || pf[-1] == 'i';
                switch ( szty[0] ) {
                   case L'h': // I/U16
                      if (sign)
                         arg.hi = (short)(arg.li<SHRT_MIN ? SHRT_MIN : arg.li>SHRT_MAX ? SHRT_MAX : arg.li);
                      else
                         arg.hu = (unsigned short)(arg.lu > USHRT_MAX ? USHRT_MAX : arg.lu);
                      no = _snwprintf_s(out1, mo, mo, f1, arg.hi); 
                   break;
                   case L'I':
                      if (szty[1] == L'6'
#ifdef _WIN64
                         || szty[1] != L'3'
#endif
                      ){ // I/U64
                         no = _snwprintf_s(out1, mo, mo, f1, arg.li); 
                         break;
                      }
                   default: // I/U32
                      if (sign)
                         arg.ii = (int)(arg.li<INT_MIN ? INT_MIN : arg.li>INT_MAX ? INT_MAX : arg.li);
                      else
                         arg.iu = (unsigned int)(arg.lu > UINT_MAX ? UINT_MAX : arg.lu);
                      no = _snwprintf_s(out1, mo, mo, f1, arg.ii); 
                   break;
                }
             break;
         }

         // print formatted argument
         //
         WCHAR *pd = out1;
         if ( thousand && *pd && wcsspn(pd, L"+-0123456789.") >= wcslen(pd) )
         {
            if (*pd == L'+') ++pd;
            
            LCID lcid = thousand == L',' ? LOCALE_INVARIANT : LOCALE_USER_DEFAULT;
            NUMBERFMTW nf;

            nf.NumDigits = 0;
            if (NULL != (pe = wcschr(pd, L'.'))) {
               nf.NumDigits = (UINT)wcslen(pe+1);
               if (nf.NumDigits > 9) nf.NumDigits = 9;
               if (nf.NumDigits <= 0) *pe = L'\0';
            }
            if (!::GetLocaleInfo(lcid, LOCALE_ILZERO, out1+1010, 8)) nf.LeadingZero = 1;
            else nf.LeadingZero = (UINT)wcstol(out1+1010, NULL, 10);
            if (!::GetLocaleInfo(lcid, LOCALE_SGROUPING, out1+1020, 8)) nf.Grouping = 3;
            else nf.Grouping = (UINT)wcstol(out1+1020, NULL, 10);
            if (!::GetLocaleInfo(lcid, LOCALE_SDECIMAL, nf.lpDecimalSep = out1+1030, 8))
               lstrcpyW(nf.lpDecimalSep, L".");
            if (!::GetLocaleInfo(lcid, LOCALE_STHOUSAND, nf.lpThousandSep = out1+1040, 8))
               lstrcpyW(nf.lpThousandSep, L",");
            if (!::GetLocaleInfo(lcid, LOCALE_INEGNUMBER, out1+1050, 8)) nf.NegativeOrder = 1;
            else nf.NegativeOrder = (UINT)wcstol(out1+1050, NULL, 10);

            int no = ::GetNumberFormatW(
               lcid, 0, pd, &nf, out1 + 1024, 1024
            );
            if ( no > 0 ) {
               pd = out1 + 1024; pd[no] = L'\0';
            }
         }
         Con::o(pd);
      }
   } while ( current < argc && current > skip+1 && !positional_mode );

e: Win::cleanup();
   (void)unused_argc, unused_argv;
   return rc;
}
